import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import streamlit as st
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, mean_squared_error
from sklearn.preprocessing import StandardScaler
import warnings

warnings.filterwarnings('ignore')


class ApexLegendAnalysis:
    def __init__(self, data_path="leg.txt"):

        self.data_path = data_path
        self.data, self.data_long = self.load_data()
        self.models_trained = False
        self.predictions_df = None

    def load_data(self):

        try:
            data = pd.read_csv(self.data_path)
            # 将数据从宽格式转换为长格式
            data_long = data.melt(id_vars=['Legend'], var_name='Time', value_name='PickRate')
            data_long['Time'] = data_long['Time'].str.extract('(\d+)').astype(int)
            return data, data_long
        except Exception as e:
            st.error(f"加载数据时出错: {e}")
            # 返回空数据帧
            return pd.DataFrame(), pd.DataFrame()

    def train_models(self):


        if self.data.empty:
            st.error("没有数据可用于训练模型")
            return 0, 0


        X = []
        y_trend = []
        y_final = []

        for legend in self.data['Legend'].values:
            pick_rates = self.data[self.data['Legend'] == legend].iloc[:, 1:].values.flatten()
            X.append(pick_rates[:5])

            trend = 1 if pick_rates[-1] > pick_rates[0] else 0
            y_trend.append(trend)
            y_final.append(pick_rates[-1])

        X = np.array(X)
        y_trend = np.array(y_trend)
        y_final = np.array(y_final)


        X_train, X_test, y_train_trend, y_test_trend, y_train_final, y_test_final = train_test_split(
            X, y_trend, y_final, test_size=0.2, random_state=42
        )


        self.scaler = StandardScaler()
        X_train_scaled = self.scaler.fit_transform(X_train)
        X_test_scaled = self.scaler.transform(X_test)


        self.lr_model = LogisticRegression()
        self.lr_model.fit(X_train_scaled, y_train_trend)
        lr_pred = self.lr_model.predict(X_test_scaled)
        self.lr_accuracy = accuracy_score(y_test_trend, lr_pred)


        self.rf_model = RandomForestRegressor(n_estimators=100, random_state=42)
        self.rf_model.fit(X_train, y_train_final)
        rf_pred = self.rf_model.predict(X_test)
        self.rf_mse = mean_squared_error(y_test_final, rf_pred)


        all_predictions = []
        for i, legend in enumerate(self.data['Legend'].values):
            pick_rates = self.data[self.data['Legend'] == legend].iloc[:, 1:].values.flatten()
            features = pick_rates[:5].reshape(1, -1)
            features_scaled = self.scaler.transform(features)

            # 使用逻辑回归预测趋势
            trend_pred = self.lr_model.predict(features_scaled)[0]
            trend_prob = self.lr_model.predict_proba(features_scaled)[0][1]  # 上升概率

            # 使用随机森林预测最终选取率
            final_rate_pred = self.rf_model.predict(features)[0]

            # 计算实际变化
            actual_change = pick_rates[-1] - pick_rates[0]

            all_predictions.append({
                'Legend': legend,
                'Trend': '上升' if trend_pred == 1 else '下降',
                'Trend_Probability': trend_prob,
                'Predicted_Final_Rate': final_rate_pred,
                'Actual_Change': actual_change
            })

        self.predictions_df = pd.DataFrame(all_predictions)
        self.models_trained = True

        return self.lr_accuracy, self.rf_mse

    def get_trend_plot(self, selected_legends):

        fig, ax = plt.subplots(figsize=(12, 6))
        for legend in selected_legends:
            legend_data = self.data_long[self.data_long['Legend'] == legend]
            ax.plot(legend_data['Time'], legend_data['PickRate'], marker='o', label=legend)

        ax.set_xlabel('段位 (1=菜鸟, 6=钻石)')
        ax.set_ylabel('选取率 (%)')
        ax.set_title('英雄选取率随段位变化趋势')
        ax.legend()
        ax.grid(True)

        return fig

    def get_recommendation_plot(self, recommended_legends):

        fig, ax = plt.subplots(figsize=(12, 6))

        for legend in recommended_legends:
            legend_data = self.data_long[self.data_long['Legend'] == legend]
            ax.plot(legend_data['Time'], legend_data['PickRate'], marker='o', label=legend, linewidth=2)

        ax.set_xlabel('段位 (1=菜鸟, 6=钻石)')
        ax.set_ylabel('选取率 (%)')
        ax.set_title('推荐英雄的选取率趋势')
        ax.legend()
        ax.grid(True)

        return fig

    def get_top_heroes(self, rank_idx):

        top_5_df = self.data[['Legend', f'Time{rank_idx + 1}']].copy()
        top_5_df.columns = ['Legend', 'PickRate']
        return top_5_df.sort_values('PickRate', ascending=False).head(5)

    def get_rising_heroes(self, limit=5):

        if not self.models_trained:
            self.train_models()

        return self.predictions_df.sort_values('Trend_Probability', ascending=False).head(limit)

    def get_all_predictions(self):

        if not self.models_trained:
            self.train_models()

        return self.predictions_df.sort_values('Trend_Probability', ascending=False)

    def get_model_performance(self):

        if not self.models_trained:
            self.train_models()

        return self.lr_accuracy, self.rf_mse


# 在Streamlit中显示英雄分析页面的函数
def show_legend_analysis():
    st.title("Apex英雄选取率分析")

    # 初始化分析类
    analysis = ApexLegendAnalysis("leg.txt")

    # 检查数据是否加载成功
    if analysis.data.empty:
        st.error("无法加载数据，请检查文件路径和格式")
        return

    # 显示数据概览
    st.subheader("数据概览")
    st.write(f"共分析 {len(analysis.data)} 位英雄的选取率数据")

    # 选择要对比的英雄
    st.subheader("英雄选取率对比")
    selected_legends = st.multiselect(
        "选择要对比的英雄",
        options=analysis.data['Legend'].tolist(),
        default=analysis.data['Legend'].tolist()[:3]  # 默认选择前3个英雄
    )

    if selected_legends:
        fig = analysis.get_trend_plot(selected_legends)
        st.pyplot(fig)

    # 显示各段位热门英雄
    st.subheader("各段位热门英雄")
    rank_options = ["菜鸟 (Time1)", "青铜 (Time2)", "白银 (Time3)", "黄金 (Time4)", "铂金 (Time5)", "钻石 (Time6)"]
    selected_rank = st.selectbox("选择段位", options=rank_options, index=5)
    rank_idx = rank_options.index(selected_rank)

    top_heroes = analysis.get_top_heroes(rank_idx)
    st.dataframe(top_heroes)

    # 训练模型并显示预测结果
    st.subheader("趋势预测分析")
    if st.button("训练模型并预测趋势"):
        with st.spinner("训练模型中..."):
            lr_accuracy, rf_mse = analysis.train_models()

        st.success("模型训练完成!")

        # 显示模型性能
        col1, col2 = st.columns(2)
        with col1:
            st.metric("逻辑回归准确率", f"{lr_accuracy:.2%}")
        with col2:
            st.metric("随机森林MSE", f"{rf_mse:.4f}")

        # 显示上升趋势英雄
        st.subheader("上升趋势英雄 (推荐)")
        rising_heroes = analysis.get_rising_heroes()
        st.dataframe(rising_heroes)

        # 显示推荐英雄的趋势图
        if not rising_heroes.empty:
            fig = analysis.get_recommendation_plot(rising_heroes['Legend'].tolist())
            st.pyplot(fig)

        # 显示所有英雄的预测结果
        st.subheader("所有英雄趋势预测")
        all_predictions = analysis.get_all_predictions()
        st.dataframe(all_predictions)


